package cn.tedu.tmall.front.mall.service.impl;

import cn.tedu.tmall.common.exception.ServiceException;
import cn.tedu.tmall.common.pojo.po.CurrentUser;
import cn.tedu.tmall.common.pojo.vo.PageData;
import cn.tedu.tmall.common.web.ServiceCode;
import cn.tedu.tmall.front.mall.dao.repository.IGoodsRepository;
import cn.tedu.tmall.front.mall.dao.repository.IOrderItemRepository;
import cn.tedu.tmall.front.mall.dao.repository.IOrderRepository;
import cn.tedu.tmall.front.mall.dao.repository.IUserAddressRepository;
import cn.tedu.tmall.front.mall.pojo.param.GoodsItemParam;
import cn.tedu.tmall.front.mall.pojo.param.OrderCreateParam;
import cn.tedu.tmall.front.mall.pojo.param.UserAddressParam;
import cn.tedu.tmall.front.mall.pojo.po.GoodsPO;
import cn.tedu.tmall.front.mall.pojo.po.OrderItemPO;
import cn.tedu.tmall.front.mall.pojo.po.OrderPO;
import cn.tedu.tmall.front.mall.pojo.po.UserAddressPO;
import cn.tedu.tmall.front.mall.pojo.vo.OrderItemVO;
import cn.tedu.tmall.front.mall.pojo.vo.OrderVO;
import cn.tedu.tmall.front.mall.service.IOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OrderService implements IOrderService {
    @Autowired
    private IGoodsRepository goodsRepository;

    @Autowired
    private IUserAddressRepository userAddressRepository;

    @Autowired
    private IOrderRepository orderRepository;

    @Autowired
    private IOrderItemRepository orderItemRepository;

    /**
     * 创建订单
     */
    @Override
    public void createOrder(CurrentUser user, OrderCreateParam orderCreateParam) {
        /*
         * todo 梳理订单创建业务逻辑
         * 入参：
         * 1. 用户信息 包含收货地址
         * 2. 商品信息 商品id、数量、单价
         * 3. 支付信息 支付方式等 可默认
         * 4. 配送信息 配送方式等 可默认
         * 5. 发票、优惠券等(可选)
         * 业务逻辑：
         * 1. 验证收货地址，地址id是否存在
         * 2.1 验证商品信息，商品id是否存在、是否上架等
         * 2.2 计算价格（基于最新的商品信息）
         *     可提供 价格中心服务 的接口进行价格计算的功能封装
         * 3. 可选功能
         * 4. 库存查验或预售，小型电商可以不考虑库存，顾客下单后让供应商发货
         * 5. 生成订单：
         *     订单表：
         *      基本信息 id(订单生成器-雪花算法-分布式唯一id生成技术之一),订单状态,创建时间,更新时间,
         *      用户相关 用户id,收货地址,联系电话,
         *      商品相关 商品id,商品价格,商品数量,总价,
         *      支付相关 支付方式,支付时间,支付金额,支付状态,
         *      配送相关 配送方式,配送时间,配送状态,
         *      可选相关 备注等
         *    注：下单时的信息要立刻保存，修改是另一个功能，可以使用快照
         */
        //todo
        // 1. 生成订单主表 OrderPO
        // 2.生成商品列表 List GoodsItemParams -> GoodsItemPOS
        // 3.保存订单数据 MyBatisPlus insert
        // 4.循环插入商品信息 MyBatisPlus insert
        // 5. 注意添加事务注解 @Transactional
        List<GoodsItemParam> goodsItemParams = orderCreateParam.getGoodsItemParams();
//        List<Long> goodsIds = new ArrayList<>();
//        for (GoodsItemParam goodsItemParam : goodsItemParams) {
//            Long goodsId = goodsItemParam.getGoodsId();
//            goodsIds.add(goodsId);
//        }
        //流处理的方式
        List<Long> goodsIds = goodsItemParams.stream()
                .map(GoodsItemParam::getGoodsId)
                .collect(Collectors.toList());

        // 查询商品是否存在
        List<GoodsPO> goodsPOS = goodsRepository.listByGoodsIds(goodsIds);
        if (goodsIds.size() != goodsPOS.size()){
            throw new ServiceException(ServiceCode.GOODS_NOT_EXIST);
        }
        // 查询商品是否上架
        for (GoodsPO goodsPO : goodsPOS) {
            if (goodsPO.getIsPutOn() != null && goodsPO.getIsPutOn() == 0){
                throw new ServiceException(ServiceCode.GOODS_NOT_PUT_ON);
            }
        }

        //判断用户信息
        UserAddressParam userAddressParam = orderCreateParam.getUserAddressParam();
        Long userId = user.getId();
        Integer addressId = userAddressParam.getAddressId();
        UserAddressPO userAddressPO = userAddressRepository.getAddressByUserIdAndAddressId(userId,addressId);
        if (userAddressPO == null){
            throw new ServiceException(ServiceCode.USER_ADDRESS_ERROR);
        }

        //计算总价：获取商品id和数量，校验id，然后计算
        BigDecimal totalPrice = BigDecimal.ZERO;
        int goodsTotalNum = 0;
        List<OrderItemPO> orderItemPOS = new ArrayList<>();
        //把goodsPOS通过流处理转换为Map，就不需要遍历List了
        Map<Long, GoodsPO> goodsPOMap = goodsPOS.stream()
                .collect(Collectors.toMap(GoodsPO::getId, Function.identity()));
        //遍历商品信息
        for (GoodsItemParam goodsItemParam : goodsItemParams) {
            Long goodsId = goodsItemParam.getGoodsId();
            Integer goodsNum = goodsItemParam.getGoodsNum();
            BigDecimal salePrice = goodsPOMap.get(goodsId).getSalePrice();
            //总价=单价*数量
            totalPrice = totalPrice.add(salePrice.multiply(new BigDecimal(goodsNum)));
            goodsTotalNum += goodsNum;
            //生成订单内单品信息
            OrderItemPO orderItemPO = buildOrderItemPO(goodsId, goodsNum, salePrice);
//            BeanUtils.copyProperties(goodsItemParam,orderItemPO);//可能由于属性名不同导致复制失败
            orderItemPOS.add(orderItemPO);
        }

        //生成订单
        OrderPO orderPO = buildOrderPO(userId, totalPrice, goodsTotalNum);
        orderPO.setOrderState(0);//应该创建常量或枚举
        Integer rows = orderRepository.save(orderPO);
        if (rows != 1)
            throw new ServiceException(ServiceCode.ORDER_CREATE_ERROR);
        //保存单品数据，与订单id绑定
        for (OrderItemPO orderItemPO : orderItemPOS) {
            orderItemPO.setOrderId(orderPO.getId());
            Integer itemRows = orderItemRepository.save(orderItemPO);
            if (itemRows != 1)
                throw new ServiceException(ServiceCode.ORDER_CREATE_ERROR);
        }
    }

    /**
     * 订单列表
     */
    @Override
    public PageData<OrderVO> list(CurrentUser user, Integer pageNum, Integer pageSize) {
        log.debug("开始处理订单列表业务，入参：user={},pageNum={},pageSize={}",user,pageNum,pageSize);
        //获取订单列表
        PageData<OrderPO> orderPOSPage = orderRepository.getOrderListByUserId(user.getId(), pageNum, pageSize);
        PageData<OrderVO> orderVOSPage = orderPagePO2VO(orderPOSPage);
        log.debug("订单列表查询成功，查询结果：{}",orderPOSPage);
        //创建订单VO列表并插入到分页结果中
        List<OrderVO> orderVOSList = new ArrayList<>();
        orderVOSPage.setList(orderVOSList);
        if (orderPOSPage!=null && !orderPOSPage.getList().isEmpty()) {
            //遍历订单列表，获取每个订单内的商品列表
            for (OrderPO orderPO : orderPOSPage.getList()) {
                OrderVO orderVO = orderPO2VO(orderPO);
                orderVOSList.add(orderVO);
                //获取订单内商品列表
                Long orderId = orderPO.getId();
                List<OrderItemPO> orderItemPOS = orderItemRepository.getOrderItemListByOrderId(orderId);
                List<OrderItemVO> orderItemVOS = new ArrayList<>();
                //商品列表不为空，则po转vo
                if (!orderItemPOS.isEmpty()){
                    for (OrderItemPO orderItemPO : orderItemPOS) {
                        OrderItemVO orderItemVO = orderItemPO2VO(orderItemPO);
                        orderItemVOS.add(orderItemVO);
                    }
                }
                //将订单的商品列表添加到订单内
                orderVO.setOrderItemVOS(orderItemVOS);
                log.debug("订单内商品列表查询成功，查询结果：{}",orderItemPOS);
            }
        } else {
            log.debug("订单列表为空，直接返回");
        }
        return orderVOSPage;
    }

    /**
     * 将订单PO分页结果转换为VO分页结果
     */
    private static PageData<OrderVO> orderPagePO2VO(PageData<OrderPO> orderPOSPage) {
        PageData<OrderVO> orderVOSPage = new PageData<>();
        BeanUtils.copyProperties(orderPOSPage,orderVOSPage);
        return orderVOSPage;
    }

    /**
     * 将订单内单品PO转换为VO
     */
    private static OrderItemVO orderItemPO2VO(OrderItemPO orderItemPO) {
        OrderItemVO orderItemVO = new OrderItemVO();
        BeanUtils.copyProperties(orderItemPO,orderItemVO);
        return orderItemVO;
    }

    /**
     * 将订单PO转换为VO
     */
    private static OrderVO orderPO2VO(OrderPO orderPO) {
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orderPO,orderVO);
        return orderVO;
    }

    /**
     * 构建订单
     */
    private static OrderPO buildOrderPO(Long userId, BigDecimal totalPrice, Integer goodsTotalNum) {
        OrderPO orderPO = new OrderPO();
        orderPO.setOrderNo(UUID.randomUUID().toString());
        orderPO.setBuyerId(userId);
        orderPO.setTotalPrice(totalPrice);
        orderPO.setGoodsNum(goodsTotalNum);
        return orderPO;
    }

    /**
     * 构建订单内单品信息
     */
    private static OrderItemPO buildOrderItemPO(Long goodsId, Integer goodsNum, BigDecimal salePrice) {
        OrderItemPO orderItemPO = new OrderItemPO();
        orderItemPO.setGoodsId(goodsId);
        orderItemPO.setGoodsNum(goodsNum);
        orderItemPO.setSaleUnitPrice(salePrice);
        return orderItemPO;
    }
}
